/**
 * Copyright (c) 2016. Visionet and/or its affiliates. All right reserved.
 * VISIONET PROPRIETARY/CONFIDENTIAL.
 */
package com.visionet.jumper.core.support.jpa;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Query;

import com.visionet.jumper.core.exception.runtime.FrameworkException;
import org.hibernate.transform.Transformers;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import com.visionet.jumper.core.domain.bean.Page;
import com.visionet.jumper.core.domain.bean.QueryBean;
import com.visionet.jumper.core.domain.search.HqlSearchable;
import com.visionet.jumper.core.domain.search.Searchable;
import com.visionet.jumper.core.domain.search.SqlSearchable;
import com.visionet.jumper.core.repository.BaseRepository;

public class SimpleBaseRepository<M> extends SimpleJpaRepository<M, String>
		implements BaseRepository<M> {

    private final EntityManager em;
    private final JpaEntityInformation<M, String> entityInformation;

    private Class<M> entityClass;

	public SimpleBaseRepository(JpaEntityInformation<M, String> entityInformation, EntityManager entityManager) {
		super(entityInformation, entityManager);

		this.entityInformation = entityInformation;
      	this.entityClass = this.entityInformation.getJavaType();
//      this.entityName = this.entityInformation.getEntityName();
//      this.idName = this.entityInformation.getIdAttributeNames().iterator().next();
        this.em = entityManager;
	}

	/**
	 * 查询特定类型持久化数据
	 * @param searchable 查询条件
	 * @param t 查询数据类型
	 * @return 数据集合
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> findALLForSpecifyType(Searchable searchable, Class<T> t) {
		Query query = this.assembleQuery(searchable);
		if(searchable instanceof HqlSearchable) {
			return query.getResultList();
		} else {
			return (List<T>) query.unwrap(org.hibernate.Query.class)
					.setResultTransformer(Transformers.aliasToBean(t))
					.list();
		}
	}

	/**
	 * 查询特定类型的分页数据
	 * @param searchable 查询条件
	 * @param c 查询数据类型
	 * @return 分页数据
	 */
	@Override
	public Page findPageForSpecifyType(Searchable searchable, Class c) {
		if(searchable == null) {
			throw new FrameworkException("search param can not be null!");
		}
		Page page = searchable.getPage();
		if(page == null) {
			page = new Page();
		}
		QueryBean q = new QueryBean();
		page.setRows(findALLForSpecifyType(searchable, c));
		page.setTotal((int) count(searchable));
		return page;
	}
	
	@Override
	public Page findAllForPage(Searchable searchable) {
		if(searchable == null) {
			throw new FrameworkException("search param can not be null!");
		}
		Page page = searchable.getPage();
		if(page == null) {
			page = new Page();
		}
		page.setRows(findAll(searchable));
		page.setTotal((int) count(searchable));
		return page;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<M> findAll(Searchable searchable) {
		Query query = this.assembleQuery(searchable);
		if(searchable instanceof HqlSearchable) {
			return query.getResultList();
		} else {
			return (List<M>) query.unwrap(org.hibernate.Query.class)
					.setResultTransformer(Transformers.aliasToBean(this.entityClass))
					.list();
		}
	}

	/**
	 * 查询条件组装
	 * @param searchable
	 * @return
	 */
	private Query assembleQuery(Searchable searchable) {
		QueryBean q = new QueryBean();
		Query query;
		if (searchable instanceof HqlSearchable) {
			query = em.createQuery(q.findBySearchParams(searchable));
		} else if (searchable instanceof SqlSearchable) {
			query = em.createNativeQuery(q.findBySearchParams(searchable));
		} else {
			throw new FrameworkException("查询类型错误");
		}
		List<Object> list = q.getConditionList();
		for (int i = 0; i < list.size(); i++) {
			query.setParameter(i + 1, list.get(i));
		}
		Page page = searchable.getPage();
		if (page != null) {
			query.setFirstResult((page.getCurPage()) * page.getPageSize());
			query.setMaxResults(page.getPageSize());
		}
		return query;
	}

	@Override
	public long count(Searchable searchable) {
		QueryBean q = new QueryBean();
		q.findBySearchParams(searchable);
		Query query;
		if (searchable instanceof HqlSearchable) {
			query = em.createQuery(q.getCountSql());
		} else if (searchable instanceof SqlSearchable) {
			query = em.createNativeQuery(q.getCountSql());
		} else {
			throw new FrameworkException("查询类型错误");
		}
		List<Object> list = q.getConditionList();
		for (int i = 0; i < list.size(); i++) {
			query.setParameter(i + 1, list.get(i));
		}
		return Long.valueOf(query.getSingleResult().toString());
	}
}
